package middlewares

import (
	"ahutoj/web/io/constanct"
	"ahutoj/web/io/request"
	"ahutoj/web/utils"
	"errors"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

// Conn
// Conn->News
// Conn->Redis topic
type WebSocket struct { //默认心跳是20s
	News map[string]chan interface{}
	Conn map[string]*websocket.Conn //单个连接
	Room map[string]map[string]struct{}

	//提供两种方式，一种是直接通过连接，一种是通过chan
	lock sync.Mutex
}

var (
	ws         WebSocket
	wsupgrader = websocket.Upgrader{
		ReadBufferSize:   1024,
		WriteBufferSize:  1024,
		HandshakeTimeout: 5 * time.Second,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
)

func InitWebSocket() {
	ws = WebSocket{
		Conn: make(map[string]*websocket.Conn),
		News: make(map[string]chan interface{}),
		Room: make(map[string]map[string]struct{}),
	}
}

//不管连接关闭，只清除连接池

// 添加连接到Room，添加消息队列
func WsHandlerConnToRoom(key string, roomKey constanct.RoomType) error {
	logger := utils.GetLogInstance()
	conn, ok := GetConn(key)
	if !ok {
		logger.Errorf("conn is not exist,key:%v", key)
		return errors.New("conn is not exist")
	}
	m := make(chan interface{})
	addConnToRoom(key, roomKey)
	addNews(key, m)
	go func() {
		defer func() {
			DelConnFromRoom(key, roomKey)
		}()
		for msg := range m {
			err := conn.WriteJSON(msg)
			if err != nil {
				// DelNews(key) 如果要在channel里存储信息的话，这个不应该关掉吧？
				return
			}
		}
	}()
	return nil
}
func WsHandlerConn(w http.ResponseWriter, r *http.Request, key string) error {
	logger := utils.GetLogInstance()
	ticker := time.NewTicker(time.Second * 20)
	conn, err := wsupgrader.Upgrade(w, r, nil)
	if err != nil {
		logger.Errorf("call wsupgrader.Upgrade failed,err:%v", err)
		return err
	}
	logger.Infof("WsUpgrade %v", key)
	addConn(key, conn)
	defer func() {
		ticker.Stop()
		DelConn(key, conn)
	}()

	for {
		select {
			//增加
		case <-ticker.C:
			if err := conn.SetWriteDeadline(time.Now().Add(time.Second * 25)); err != nil {
				return nil
			}
			if err := conn.WriteJSON(request.WebSocketReq{
				Type: 0,
			}); err != nil {
				return nil
			}
		}
	}
}

func addConn(key string, c *websocket.Conn) {
	ws.lock.Lock()
	ws.Conn[key] = c //不幂等，但是需要每次连接都成功
	ws.lock.Unlock()
}

func DelConn(key string, c *websocket.Conn) {
	ws.lock.Lock()
	if conn, ok := ws.Conn[key]; ok {
		conn.Close()
		if conn == c {
			delete(ws.Conn, key)
		}
	}
	ws.lock.Unlock()
}

func GetConn(key string) (c *websocket.Conn, exist bool) {
	ws.lock.Lock()
	c, exist = ws.Conn[key]
	ws.lock.Unlock()
	return
}

func addConnToRoom(key string, roomKey constanct.RoomType) {
	ws.lock.Lock()
	ws.Room[string(roomKey)][key] = struct{}{}
	ws.lock.Unlock()
}

func DelConnFromRoom(key string, roomKey constanct.RoomType) {
	ws.lock.Lock()
	if _, ok := ws.Room[string(roomKey)]; ok {
		delete(ws.Room[string(roomKey)], key)
	}
	ws.lock.Unlock()
}
func GetRoom(roomKey constanct.RoomType) (c map[string]struct{}, exist bool) {
	ws.lock.Lock()
	c, exist = ws.Room[string(roomKey)]
	ws.lock.Unlock()
	return
}

func DelRoom(rooKey string) {
	ws.lock.Lock()
	delete(ws.Room, rooKey)
	ws.lock.Unlock()
}

func addNews(key string, m chan interface{}) {
	ws.lock.Lock()
	if _, exist := ws.News[key]; !exist {
		ws.News[key] = m
	}
	ws.lock.Unlock()
}
func DelNews(key string) {
	ws.lock.Lock()
	if m, exist := ws.News[key]; exist {
		close(m)
		delete(ws.News, key)
	}
	ws.lock.Unlock()
}
func GetNews(key string) (m chan interface{}, exist bool) {
	ws.lock.Lock()
	m, exist = ws.News[key]
	ws.lock.Unlock()
	return
}

func GetAllConn() (c map[string]*websocket.Conn) {
	ws.lock.Lock()
	c = ws.Conn
	ws.lock.Unlock()
	return
}
